package Checkers;

import java.util.Arrays;
//import java.sql.*;
import java.util.LinkedList;
import java.util.ListIterator;

public class Stratagem {
    
    private static final boolean randomize = true;

    private static int DEPTH;
    //private static boolean USEDB;
    //private static Connection _dbCon;
    //private static Statement _dbStmt;

    //to do:
    //a-b pruning, depth limit, time limit, get board to refresh after player 1 move, improve efficiency
    //double jumps still a little glitchy
    //make and evolve polynomial
    public static Move getBestMove(Board board, int depth, int alpha0, int beta0, int[] poly)
    {
        int min=9999999;
        int max=-9999999;
        int maxMove=-1;
        int minMove=-1;
        int best=-1;
        int alpha=alpha0;
        int beta=beta0;

        //generate all child moves
        LinkedList<Move> allMoves = ValidMoves.getMoves(board);

        //end of game
        if(allMoves.size()==0)
            return null;
        //else...    
            
        //find best move
        for(int i=0;i<allMoves.size();i++)
        {
            int value=0;
            //recursion
            if(depth==0)
                value=evalMove(board,allMoves.get(i),poly);
            else
            {
                Board nextBoard=board.clone();
                nextBoard.makeMove(allMoves.get(i));
                Move nextMove=getBestMove(nextBoard, depth-1, alpha, beta, poly);
                if(nextMove==null)
                {
                    value=evalBoard(nextBoard,poly);
                }
                else
                {
                    value=evalMove(nextBoard,nextMove,poly);
                }
            }
//            System.out.println("Choice: "+ value);
            
            if(value<min || randomize && value==min && Math.random()<0.3) //random factor for equivalent positions
            {
                min=value;
                minMove=i;
                beta=max;
            }
            if(value>max || randomize && value==max && Math.random()<0.3)
            {
                max=value;
                maxMove=i;
                alpha=min;
            }
            //if (beta <= alpha)
            //  break;
        }
        if(board.getPlayer()==1)
        {
            best=maxMove;
        }
        else
        {
            best=minMove;
//            System.out.println("I'm minimizing");
        }

        //return best move
//        System.out.println("Chosen: "+bestBoard);

        if(best<0 || best>allMoves.size()) //debug
        {
            System.out.println("ERROR!");
            System.out.println("allMoves.size()="+allMoves.size());
            System.out.println("min="+min);
            System.out.println("max="+max);
            System.out.println("Position Eval to: "+best);
        }

        return allMoves.get(best).getCopy();
    }

    public static int evalBoard(Board b0, int[] poly)
    {
//        int red = evaluate(b0,(byte)1,poly);
//        int black = evaluate(b0,(byte)2,poly);
//        return red-black;
        return evaluate(b0,b0.getPlayer(),poly);
    }
    
    public static int evalMove(Board b0,Move m,int[] poly)
    {
        Board b1=b0.clone();
        b1.makeMove(m);
        return evalBoard(b1,poly);
    }

    //added incentive for kings to advance in the endgame
    //closer to last row = higher score (range from 4-1 for half of the board)
    public static int kingScore(Board b,int player)
    {
        int n=0;
        if(player==2)
        {
            for(int y=0;y<=3;y++)
                for(int x=0;x<=7;x++)
                    if(b.getPieceAt(y,x)==5)
                        n+=4-y;
        }
        else
        {
            for(int y=7;y>=4;y--)
                for(int x=0;x<=7;x++)
                    if(b.getPieceAt(y,x)==4)
                        n+=y-3;
        }
        return n;
    }

    //added incentive for pawns to advance to kings
    //closer to last row = higher score
    public static int pawnScore(Board b,int player)
    {
        int n=0;
        if(player==2)
        {
            for(int y=1;y<=7;y++)
                for(int x=0;x<=7;x++)
                    if(b.getPieceAt(y,x)==2)
                        n+=8-y;
        }
        else
        {
            for(int y=6;y>=0;y--)
                for(int x=0;x<=7;x++)
                    if(b.getPieceAt(y,x)==1)
                        n+=y+1;
        }
        return n;
    }

    /**
     * evaluate
     * returns a polynomial score of various terms
     */
    public static int evaluate(Board b, byte player, int[] poly) {
        byte[] board = b.getByteBoard();
        byte adv=0, apex=0, back=0, cent=0, cntr=0, corn=0, cramp=0;
        byte deny=0, dia=0, diav=0, dyke=0;
        byte exch=0, expos=0, fork=0, gap=0, guard=0, hole=0, kcent=0;
        byte mob=0, mobil=0, move=0, node=0;
        byte oreo=0, pole=0, threat=0;
        
        byte passive = player;      // player is passive
        if (b.getPlayer() != player)    // or we are passive
            passive = b.getPlayer();
        
        // ADV
        // +1 for passive in rows 5, 6 (red); -1 for passive in rows 3, 4 (red)
        for (int i = 26; i>18; i--)
            if (board[i] == passive)
                if (passive == 1)       // red, at the top
                    adv--;
                else                        // black, at the top
                    adv++;
        for (int i = 17; i>9; i--)
            if (board[i] == passive)
                if (passive == 1)       // red, at the bottom
                    adv++;
                else                        // black, at the bottom
                    adv--;
                    

        // APEX
        // no kings && active in 29 OR 7 && passive in neither
        if ((board[29] != passive && board[7] != passive) && (board[29] == player || board[7] == player))
            apex = -1;
        if (apex == -1) {
            for (int i =1; i<36; i++) {
                if (i==9||i==18|i==27) {i++; continue; }
                if (board[i] != 4 && board[i] != 5)
                    apex++;
                
                if (board[i] == 4 && player == 1)   {   // an active red king
                    back++;
                    guard++;
                } else if (board[i] == 5 && player == 2)    {   // an active black king
                    back++;
                    guard++;
                }
            }
            if (apex == 31) // means no kings were found
                apex = -1;
            else
                apex = 0;
        }

        // BACK
        // no active kings && passive pieces in 1 && 3 OR 33 && 35
        if (back == 0 && (
            (board[35] == passive || board[35] == passive+3 && board[33] == passive || board[33] == passive+3) || 
            (board[1] == passive || board[1] == passive+3 && board[3] == passive || board[1] == passive+3)))
            back = 1;
            

        // CENT
        // +1 for passive in 11, 12, 15, 16, 20, 21, 24, 25
        for (int i = 11; i<24; i+=4) {
            if (board[i] == passive)        // passive cnt
                cent++;
            if (board[i+1] == passive)
                cent++;
            if (board[i] == player)     // active cnt
                cntr++;
            if (board[i+1] == player)
                cntr++;
            if (i == 15)
                i++;
        }
        
        // CNTR
        // +1 for active or active can move into 11, 12, 15, 16, 20, 21, 24, 25 (include jumps later?)
        // red + 30, 29, 28, 26, 19, 17; black + 6, 7, 8, 10, 17, 19
        if (player == 1) {  // active player is red
            if (board[30] == 1 || board[30]==4) cntr++;
            if (board[29] == 1 || board[29]==4) cntr++;
            if (board[28] == 1 || board[28]==4) cntr++;
            if (board[26] == 1 || board[26]==4) cntr++;
            if (board[19] == 1 || board[19]==4) cntr++;
            if (board[17] == 1 || board[17]==4) cntr++;
            
            // CRAMP for black, passive
            if ((board[14] == 2 || board[14]==5) && 
                (board[15] == 2 || board[15]==5 || board[10] == 2 || board[10]==5) && 
                ((board[19] == 1 || board[19]==4) && (board[23] == 1 || board[23]==4) && (board[24] == 1 || board[24]==4) && (board[28] == 1 || board[28]==4)))
                cramp = 2;
            
        } else {
            if (board[17] == 2 || board[17]==5) cntr++;
            if (board[19] == 2 || board[19]==5) cntr++;
            if (board[6] == 2 || board[6]==5) cntr++;
            if (board[7] == 2 || board[7]==5) cntr++;
            if (board[8] == 2 || board[8]==5) cntr++;
            if (board[10] == 2 || board[10]==5) cntr++;
            
            // CRAMP for red, passive
            if ((board[22] == 1 || board[22]==4) && 
                (board[21] == 1 || board[21]==4 || board[26] == 1 || board[26]==4) && 
                ((board[8] == 2 || board[8] == 5) && (board[12] == 2 || board[12] ==5) && (board[13] == 2 ||board[13]==5) && (board[17] == 2 || board[17]==5)))
                cramp = 2;
        }
        
        // -----CORN (NOT USED)--------
        // wtf is material credit?
        
        // CRAMP (see CNTR)
        // +2 for (red) passive in 22 && 21 OR 26 && (black) active in 8, 12, 13, 17
        // (black) passive in 14 && 15 OR 10 && (red) active in 19, 23, 24, 28
        
        // DENY (see MOB)
        // +1 per squre in MOB if on next move, a piece occupying square can be captured without exchange
        
        // DIA (see DIAV)
        // +1 per passive piece located in diagonal files terminating in double-corner squares
        
        // DIAV
        // +1/2 per passive 2 squares away from double corner diagonal files
        // +1 per passive 1 square away
        // +3/2 per passive in double corner file
        float diavtemp = 0;
        for (int i=4; i<=32; i+=4)
            if (board[i]==passive || board[i]==passive+3) {
                dia++;
                diavtemp+=1.5;
                if (i<32 && board[i-1]==passive || board[i-1]==passive+3)
                    diavtemp+=1;
                if (i>4 && board[i+1]==passive || board[i+1]==passive+3)
                    diavtemp+=1;
                if (i<=20 && (board[i-2]==passive || board[i-2]==passive+3))
                    diavtemp+=.5;
                if (i>=16 && (board[i+2]==passive || board[i+2]==passive+3))
                    diavtemp+=.5;
            }
        diav = (byte)diavtemp;
        
        // DYKE  (see GIGANTIC ITERATION)
        // +1 per passive string of 3 pieces in adjacent diagonal squares
        
        // EXCH (see MOB)
        // +1 per square to which active side may advance a piece and force an exchange
        
        // EXPOS  (see GIGANTIC ITERATION)
        // +1 per passive piece flanked along a diagonal by two empty squares
        
        // FORK (TODO) eval in ValidMoves
        // +1 per situation in which 2 adjacent passive pieces in row and 3 empty squares such that active player
        // in occupying one of them, threaten sure capture of one or the other passive pieces
         for (int i=30; i>5; i--) {
             if ((board[i]==passive || board[i]==passive+3) && board[i-6]!=-1 && (board[i-1]==passive || board[i-1]==passive+3) && ((board[i-5]==0 && board[i+5]==0 && board[i+3]==0 && board[i-3]!=-1 && board[i+1]==player || board[i+1]==player+3) || (board[i-4]==0 && board[i+4]==0 && board[i-6]==0 && board[i-2]==player || board[i-2]==player+3))) {
                 fork++;
             }
         }        
         
        // GAP  (see GIGANTIC ITERATION)
        // +1 per single, empty square that separates two passive pieces along a diagonal,
        // or separates a passive piece from the edge of the board
        
        // GUARD (see OREO)
        // +1 if no active kings && if either the Bridge (BACK) or Triangle of Oreo (OREO) is occupied by passive
            
        // HOLE  (see GIGANTIC ITERATION)
        // +1 per empty square surrounded by 3 or more passive
        
        // KCENT
        // +1 for passive king in 11, 12, 15, 16, 20, 21, 24, 25
        for (int i = 11; i<24; i+=4) {
            if (board[i] == passive + 3)    // passive king
                kcent++;
            if (board[i+1] == passive + 3)
                kcent++;
            if (i == 15)
                i++;
        }
        

        
        // MOB
        // +1 per square to which active side could move 1 or more pieces normally (disregard jump possibilities)
        byte tboard[] = board.clone();
        if (player==2)  // reverse the board for black
            for (int i=0; i<37; i++)
                board[i]=tboard[36-i];
        
        for (int i = 1; i < 36; i++ ) {
            if (board[i] == 0) {
                if ((i<32 && (board[i+5] == player || board[i+4] == player || board[i+5] == player+3 || board[i+4] == player+3)) 
                        || (i>4 && (board[i-4] == player+3 || board[i-5] == player+3))) 
                {
                    mob++;
                    
                    // top left to bottom right 
                    if ((i<32 && (board[i+5] == player || board[i+5] == player+3)) 
                            && (i>4 && (board[i-5] == passive || board[i-5] == passive+3)))
                    {
                        // EXCHANGE
                        if (i<28 && (board[i+10]==player || board[i+10]==player+3 || (board[i+9]==player || board[i+9]==player+3 && board[i+1]==0)))
                            exch++;
                        // DENY
                        if (i>8 && ((board[i-10] != -1 && board[i-10] != passive && board[i-10] != passive+3)
                                && ((board[i-9] != passive && board[i-9] != passive+3) 
                                        || (board[i-9]==passive || board[i-9]==passive+3 && (board[i-1]==-1 || board[i-1]!=0))
                                        || (board[i-9]!=0 && board[i-1]!=passive+3))))
                            deny++;
                        // THREAT
                        if (i>8 && board[i-10] == 0)
                            threat++;                           
                    }
                    // top right to bottom left 
                    if ((i<32 && (board[i+4] == player || board[i+4] == player+3)) 
                            && (i>4 && (board[i-4] == passive || board[i-4] == passive+3))) 
                    {
                        if (i<28 && (board[i+8]==player || board[i+8]==player+3 || (board[i+9]==player || board[i+9]==player+3 && board[i+1]==0)))
                            exch++;
                        
                        if (i>8 && ((board[i-8] != -1 && board[i-8] != passive && board[i-8] != passive+3)
                                && ((board[i-9] != passive && board[i-9] != passive+3) 
                                        || (board[i-9]==passive || board[i-9]==passive+3 && (board[i+1]==-1 || board[i+1]!=0))
                                        || (board[i-9]!=0 && board[i+1]!=passive+3))))
                            deny++;

                        if (i>8 && board[i-8] == 0)
                            threat++;
                    }
                    
                    // kings only EXCH
                    if (i>8 && i<32 && 
                            ((board[i-5]==player+3 &&
                                    ((board[i+5]==passive+3 && board[i-4]!=passive && board[i-4]!=passive+3 && board[i-10]==player+3 || board[i-9]==player+3 && board[i-1]==0)
                                            || (board[i+4]==passive+3 && board[i-4]!=passive && board[i-4]!=passive+3 && board[i-8]==player+3 || board[i-9]==player+3 && board[i+1]==0)))
                            || board[i-4]==player+3 &&
                                    ((board[i+4]==passive+3 && board[i-5]!=passive && board[i-5]!=passive+3 && board[i-8]==player+3 || board[i-9]==player+3 && board[i+1]==0)
                                            || (board[i+5]==passive+3 && board[i-5]!=passive && board[i-5]!=passive+3 && board[i-10]==player+3 || board[i-9]==player+3 && board[i-1]==0)))) {
                        exch++;
                    }
                    
                    // kings only DENY
                    if (i>4 && i<28 && board[i-5]==player+3 && board[i+5]==passive+3 && board[i+10]!=passive+3 && board[i+9]!=passive+3 && board[i+1]!=passive || board[i+1]!=passive+3)
                        deny++;
                    else if (i>4 && i<28 && board[i-4]==player+3 && board[i+4]==passive+3 && board[i+8]!=passive+3 && board[i+9]!=passive+3 && board[i-1]!=passive || board[i-1]!=passive+3)
                        deny++;
                    
                    // kings only THREAT
                    if (i>4 && i<28 && board[i-5]==player+3 && (board[i+5]==passive || board[i+5]==passive+3) && board[i+10]==0)
                        threat++;
                    else if (i>4 && i<28 && board[i-4]==player+3 && (board[i+4]==passive || board[i+4]==passive+3) && board[i+8]==0)
                        threat++;
                } 
            }
        }
        
        if (player==2)  // reverse-reverse the board for black
            for (int i=0; i<37; i++)
                board[i]=tboard[i];
        
        // MOBIL
        // diff between MOB and DENY
        mobil = (byte)(mob-deny);
        
        // ------MOVE (NOT USED)-----
        // +1 if total piece count is even (<24) (2, 3 for king) and if an odd number of pieces are in move system
        // defined by vertical files in 28, 29, 30, 31
        
        
        // NODE  (see GIGANTIC ITERATION)
        // +1 per passive piece surrounded by atleast 3 empty squares

        // OREO
        // +1 if no passive kings and passive in 29, 33, 34 (red) or 2, 3, 7 (black)
        if (passive == 1)   // passive red
            if (board[29] == 1 && board[33] == 1 && board[34] == 1) {
                oreo = 1;
                for (int i = 1; i<36; i++)
                    if (board[i] == 4) {
                        oreo = 0;
                        break;
                    }       
            }
        else
            if (board[2] == 2 && board[3] == 2 && board[7] == 2) {
                oreo = 1;
                for (int i = 1; i<36; i++)
                    if (board[i] == 5) {
                        oreo = 0;
                        break;
                    }
            }

        // GUARD
        if (back == 1 || (guard == 0 && oreo == 1))
            guard = 1;
        
        // POLE (see GIGANTIC ITERATION)
        // +1 per passive piece completely surrounded by empty squares
        
        // GIGANTIC ITERATION block for various parameters
        for (int i = 1; i < 36; i++) {
            byte empty = 0, friendly = 0, leftdiag = 0, rightdiag = 0;
            if (i==9||i==18||i==27) {i++; continue; }
            
            // a passive piece
            if (board[i] == passive || board[i] == passive+3) {
                if (i > 4) {    // exclude bottom row
                    if (i > 5 && board[i-5] == 0) {                  // back right
                        empty++; leftdiag++;
                    }                   
                    else if ((i > 5 && board[i-5] == passive) || (i < 31 && board[i+5] == passive+3)) 
                        friendly++;
                    
                    if (i > 4 && board[i-4] == 0) {                  // back left
                        empty++; rightdiag++;
                    }                   
                    else if ((i > 4 && board[i-4] == passive) || (i < 32 && board[i+4] == passive+3)) 
                        friendly++;
                }
                if (i < 32) {   // exclude top row
                    if (board[i+4] == 0) {                  // forward right
                        empty++; rightdiag++;
                    }
                    else if (board[i+4] == passive || board[i+5] == passive+3) 
                        friendly++;
                    
                    if (board[i+5] == 0) {                  // forward left
                        empty++; leftdiag++;
                    }
                    else if (board[i+5] == passive || board[i+5] == passive+3) 
                        friendly++;
                }
                // NODE
                if (empty > 3) {
                    node++;
                    // POLE
                    if (empty == 4)
                        pole++;
                }
                // EXPOS
                if (leftdiag == 2 || rightdiag == 2)
                    expos++;
                // DYKE
                if (friendly >= 2)
                    dyke++;
            }
            
            // an empty space
            else if (board[i] == 0) {                       
                if (i > 4) {
                    if (board[i-5] == passive || board[i-5]==passive+3) {                   // back right
                        friendly++; leftdiag++;
                    }
                    
                    if (board[i-4] == passive || board[i-4]==passive+3) {                   // back left
                        friendly++; rightdiag++;
                    }                   
                }
                if (i < 32) {
                    if (board[i+5] == passive || board[i+5]==passive+3) {
                        friendly++; leftdiag++;
                    }
                    
                    if (board[i+4] == passive || board[i+4]==passive+3) {
                        friendly++; rightdiag++;
                    }
                }
                // HOLE
                if (friendly >= 3)
                    hole++;
                // GAP
                if (rightdiag == 2 || leftdiag == 2 || 
                    (rightdiag == 1 && i>4 && board[i-4] == -1) || (leftdiag == 1 && i>4 && board[i-5] == -1))
                    gap++;
            }
            
        }
        
        // THRET (TODO) eval in ValidMoves
        // +1 per square to which an active piece may be moved and then threaten capture of passive piece in subsequent move

        //piece count difference
        byte b0[]=b.getByteBoard();
        int diff=0,reds=0,blacks=0;
        for (int i=1; i<=35; i++)
        {
            if(b0[i]==1)
                reds+=1;
            else if (b0[i]==4)
                reds+=3;
            else if (b0[i]==2)
                blacks+=1;
            else if (b0[i]==5)
                blacks+=3;
        }
        if(player==1)
        {
            diff=reds-blacks;
        }
        else
        {
            diff=blacks-reds;
        }
        
        //piece ratio
        int ratio=0;
        if(player==1)
        {
            if(blacks==0)
                ratio=99999;
            else
                ratio=10*reds/blacks;
        }
        else
        {
            if(reds==0)
                ratio=99999;
            else
                ratio=10*blacks/reds;
        }

        //finisher (should be negative weighted)
        int finisher=0;
        if(ratio>=30)
        {
            byte p;
            int dist=0;
            boolean found=false;
            //locate enemy piece
            for(int y=0;y<=7;y++)
            {
                for(int x=0;x<=7;x++)
                {
                    p=b.getPieceAt(y,x);
                    if(player==1 && (p==2 || p==5) || player==2 && (p==1 || p==4)) //enemy found
                    {
                        for(int y1=0;y1<=7;y1++) //calc paeudo-distance to all allies, inverse-inverse-square
                        {
                            for(int x1=0;x1<=7;x1++)
                            {
                                if(player==1 && b.getPieceAt(y1,x1)==4 || player==2 && b.getPieceAt(y1,x1)==5)
                                {
                                    dist+=Math.pow((x-x1)+(y-y1),2);
                                }
                            }
                        }
                        found=true;
                        break;
                    }
                    if(found)
                        break;
                }
            }
            finisher=dist;
        }

        if(1==0)
        {
            System.out.println("---- BOARD EVALUATION ----");
            System.out.println(" Player = "+player);
            System.out.println("diff = "+diff);
            System.out.println("adv = "+adv);
            System.out.println("apex = "+apex);
            System.out.println("back = "+back);
            System.out.println("cent = "+cent);
            System.out.println("cntr = "+cntr);
            System.out.println("kcent = "+kcent);
            System.out.println("mob = "+mob);
            System.out.println("oreo = "+oreo);
            System.out.println("guard = "+guard);
            System.out.println("node = "+node);
            System.out.println("expos = "+expos);
            System.out.println("dyke = "+dyke);
            System.out.println("hole = "+hole);
            System.out.println("gap = "+gap);
            System.out.println("pole = "+pole);
            System.out.println("cramp = "+cramp);
            System.out.println("deny = "+deny);
            System.out.println("dia = "+dia);
            System.out.println("diav = "+diav);
            System.out.println("exch = "+exch);
            System.out.println("mobil = "+mobil);
            System.out.println("threat = "+threat);
    
            System.out.println("-----------------------");
    
            System.out.println("corn = "+corn);
            System.out.println("fork = "+fork);
            System.out.println("move = "+move);
            System.out.println("-------- END --------");
        }
        
        //calculate the polynomial
        int result =
               poly[0]*diff +
               poly[1]*adv +
               poly[2]*apex +//low
               poly[3]*back +
               poly[4]*cent +//low
               poly[5]*cntr +
               poly[6]*kcent +//high
               poly[7]*oreo +//low
               poly[8]*guard +
               poly[9]*node +
               poly[10]*expos +
               poly[11]*dyke +
               poly[12]*hole +
               poly[13]*gap +//low
               poly[14]*mob +//low
               poly[15]*pole +
               poly[16]*deny +//low
               poly[17]*mobil +//high
               poly[18]*threat +
               poly[19]*exch +//low
               poly[20]*dia +
               poly[21]*diav +
               poly[22]*cramp +
               poly[23]*kingScore(b,player) +
               poly[24]*pawnScore(b,player) +
               poly[25]*ratio +
               poly[26]*fork +
               poly[27]*finisher ;
               
         if(player==2)
            result*=-1;
         
         return result;
    }
    
    /**
     * The database has two tables: states and counters
     * states:      id, board (string format)
     * counters:    board (from id), counter (to id), weight
     */
    /*
    public static void connectDB(String url, String user, String pw) throws ClassNotFoundException, SQLException{
        Class.forName("com.mysql.jdbc.Driver");
        _dbCon = DriverManager.getConnection(url, user, pw);
        _dbStmt = _dbCon.createStatement();
        USEDB = true;
    }
    
    public static void disconnectDB() throws SQLException {
        _dbCon.close();
        USEDB = false;
    }
    
    private static void insertBoard(Board board, StateNode counters[]) throws SQLException {
        String strBoard = board.toDBString();
        //System.out.println("sql: querying state id");
        ResultSet rs = _dbStmt.executeQuery("SELECT id FROM states WHERE board LIKE " +strBoard);
        int id = 0;

        // check if this board state is already in the db
        if (rs.next()) {
            id = rs.getInt("id");
        } else {
            _dbStmt.executeUpdate("INSERT INTO states (board) VALUES ("+strBoard+")");
            rs = (_dbStmt.executeQuery("SELECT id FROM states WHERE board LIKE " +strBoard));
            if (!rs.next()) System.exit(1); // BIG FAIL
            id = rs.getInt("id");
        }
        
        // and find the id's for every counter, or insert into states table if it's not there
        int[] counterIDs = new int[counters.length];
        for (int i = 0; i < counters.length; i++) {
            //System.out.println("sql: querying counter["+i+"] id = "+counters[i].getBoard().toDBString());
            rs = _dbStmt.executeQuery("SELECT id FROM states WHERE board LIKE " +counters[i].getBoard().toDBString());
            if (rs.next())
                counterIDs[i] = rs.getInt("id");
            else {
                _dbStmt.executeUpdate("INSERT INTO states (board) VALUES (" +counters[i].getBoard().toDBString()+")");
                i--;    // go back and try again now that this state has been inserted
                //System.out.println("sql: inserting new state");
            }
        }

        // if this state's counters are in the table, update, otherwise insert
        rs = _dbStmt.executeQuery("SELECT COUNT(board) AS c FROM counters WHERE board=" +id);
        int numCounters = 0;
        if (rs.next())
            numCounters = rs.getInt("c");
        
        if (numCounters > 0) {
            //System.out.println("sql: start updating counter");
            for (int i = 0; i< counters.length; i++) {
                _dbStmt.executeUpdate("UPDATE counters " +
                        "SET weight=" +counters[i].getValue()+
                        " WHERE board=" +id+
                                " AND counter=" +counterIDs[i]);

            }
            //System.out.println("sql: done updating counter");
        } else {
            //System.out.println("sql: start inserting counters");
            //System.out.println("sql: starting the loop: inserting counters");
            for (int i = 0; i < counters.length; i++) {
                _dbStmt.executeUpdate("INSERT " +
                        "INTO counters (board, counter, weight) " +
                        "VALUES (" +id+ ", " +counterIDs[i]+ ", " +counters[i].getValue()+")");

            }
            //System.out.println("sql: done inserting new counters");
        }
    }
    
    public static void testDB() throws SQLException {
        System.out.println("The DB Says:");
        ResultSet rs = _dbStmt.executeQuery("SELECT * FROM states");
        while (rs.next()) {
            int id = rs.getInt("id");
            String board = rs.getString("board");
            System.out.println(id+" "+board);
        }
    }
    */
}
